#include "EpilTableObject.h"
#include "EpilPointerHelper.h"
#include "EpilObjectHelper.h"
#include "EpilInterpreter.h"
#include "EpilInterpreterException.h"


EpilTableObject::EpilTableObject( EpilInterpreter * interpreter )
: EpilReferenceObject( interpreter )
{
}


EpilTableObject::~EpilTableObject()
{
	for( EpilObjectMap::iterator it = m_fields.begin(); it != m_fields.end(); ++it )
	{
		EpilObject * key = it->first;
		EpilObject * value = it->second;
		key->ReleaseCopy();
		value->ReleaseCopy();
	}
}


EpilObject * EpilTableObject::GetField( const EpilObject * key ) const
{
	for( EpilObjectMap::const_iterator it = m_fields.begin(); it != m_fields.end(); ++it )
	{
		const EpilObject * keyObj = it->first;
		if( *keyObj == *key )
		{
			return it->second->CreateCopy();
		}
	}
	return this->GetInterpreter()->CreateNilObject();
}


EpilObject * EpilTableObject::GetField( bool key ) const
{
	for( EpilObjectMap::const_iterator it = m_fields.begin(); it != m_fields.end(); ++it )
	{
		if( it->first->GetType() != EOT_Boolean )
		{
			continue;
		}
		const EpilBooleanObject * keyObj = static_cast<const EpilBooleanObject *>( it->first );
		if( keyObj->GetValue() == key )
		{
			return it->second->CreateCopy();
		}
	}
	return this->GetInterpreter()->CreateNilObject();
}


EpilObject * EpilTableObject::GetField( int key ) const
{
	for( EpilObjectMap::const_iterator it = m_fields.begin(); it != m_fields.end(); ++it )
	{
		if( it->first->GetType() != EOT_Number )
		{
			continue;
		}
		const EpilNumberObject * keyObj = static_cast<const EpilNumberObject *>( it->first );
		if( EpilObjectHelper::IsDoubleEquals( keyObj->GetValue(), key ) )
		{
			return it->second->CreateCopy();
		}
	}
	return this->GetInterpreter()->CreateNilObject();
}


EpilObject * EpilTableObject::GetField( double key ) const
{
	for( EpilObjectMap::const_iterator it = m_fields.begin(); it != m_fields.end(); ++it )
	{
		if( it->first->GetType() != EOT_Number )
		{
			continue;
		}
		const EpilNumberObject * keyObj = static_cast<const EpilNumberObject *>( it->first );
		if( EpilObjectHelper::IsDoubleEquals( keyObj->GetValue(), key ) )
		{
			return it->second->CreateCopy();
		}
	}
	return this->GetInterpreter()->CreateNilObject();
}


EpilObject * EpilTableObject::GetField( const tstring & key ) const
{
	for( EpilObjectMap::const_iterator it = m_fields.begin(); it != m_fields.end(); ++it )
	{
		if( it->first->GetType() != EOT_String )
		{
			continue;
		}
		const EpilStringObject * keyObj = static_cast<const EpilStringObject *>( it->first );
		if( keyObj->GetValue() == key )
		{
			return it->second->CreateCopy();
		}
	}
	return this->GetInterpreter()->CreateNilObject();
}


void EpilTableObject::SetField( EpilObject * key, EpilObject * value )
{
	for( EpilObjectMap::iterator it = m_fields.begin(); it != m_fields.end(); ++it )
	{
		const EpilObject * keyObj = it->first;
		if( *keyObj == *key )
		{
			it->second->ReleaseCopy();
			it->second = value;
			return;
		}
	}
	
	m_fields.insert( make_pair( key, value ) );
}


void EpilTableObject::SetField( bool key, EpilObject * value )
{
	for( EpilObjectMap::iterator it = m_fields.begin(); it != m_fields.end(); ++it )
	{
		if( it->first->GetType() != EOT_Boolean )
		{
			continue;
		}
		const EpilBooleanObject * keyObj = static_cast<const EpilBooleanObject *>( it->first );
		if( *keyObj == key )
		{
			it->second->ReleaseCopy();
			it->second = value;
			return;
		}
	}
	
	m_fields.insert( make_pair( this->GetInterpreter()->CreateBooleanObject( key ), value ) );
}


void EpilTableObject::SetField( int key, EpilObject * value )
{
	for( EpilObjectMap::iterator it = m_fields.begin(); it != m_fields.end(); ++it )
	{
		if( it->first->GetType() != EOT_Number )
		{
			continue;
		}
		const EpilNumberObject * keyObj = static_cast<const EpilNumberObject *>( it->first );
		if( EpilObjectHelper::IsDoubleEquals( keyObj->GetValue(), key ) )
		{
			it->second->ReleaseCopy();
			it->second = value;
			return;
		}
	}
	
	m_fields.insert( make_pair( this->GetInterpreter()->CreateNumberObject( key ), value ) );
}


void EpilTableObject::SetField( double key, EpilObject * value )
{
	for( EpilObjectMap::iterator it = m_fields.begin(); it != m_fields.end(); ++it )
	{
		if( it->first->GetType() != EOT_Number )
		{
			continue;
		}
		const EpilNumberObject * keyObj = static_cast<const EpilNumberObject *>( it->first );
		if( *keyObj == key )
		{
			it->second->ReleaseCopy();
			it->second = value;
			return;
		}
	}
	
	m_fields.insert( make_pair( this->GetInterpreter()->CreateNumberObject( key ), value ) );
}


void EpilTableObject::SetField( const tstring & key, EpilObject * value )
{
	for( EpilObjectMap::iterator it = m_fields.begin(); it != m_fields.end(); ++it )
	{
		if( it->first->GetType() != EOT_String )
		{
			continue;
		}
		const EpilStringObject * keyObj = static_cast<const EpilStringObject *>( it->first );
		if( *keyObj == key )
		{
			it->second->ReleaseCopy();
			it->second = value;
			return;
		}
	}
	
	m_fields.insert( make_pair( this->GetInterpreter()->CreateStringObject( key ), value ) );
}


EpilObject * EpilTableObject::OperateUnary( EpilUnaryOperator op )
{
	throw EpilInterpreterException( t("Not implemented.") );
}


EpilObject * EpilTableObject::OperateBinary( EpilBinaryOperator op, EpilObject * that )
{
	throw EpilInterpreterException( t("Not implemented.") );
}


tstring EpilTableObject::ToString() const
{
	tstringstream ret;
	ret << t("Table: 0x") << this;
	return ret.str();
}